import React, { CSSProperties } from 'react';
import './App.css';
import * as _r from './Core/Core';
import DocumentTitle from 'react-document-title';

import GlobalStyle from './Global'
import PopupDialog from './PopupDialog'
import Board, { BoardStyle } from './Board'

export class GameStyle {
    constructor(Global = new GlobalStyle()) {
        this.global = Global;
        this.board = new BoardStyle(Global);
    }
    global: GlobalStyle;
    board: BoardStyle;
}

class SetUpData {
    nx: number = 30;
    ny: number = 30;
    borderReflect: boolean = true;
}

class SetUp extends React.Component<{ onSubmit: (data: SetUpData) => void}, SetUpData> {
    constructor(props: any) {
        super(props);
        this.state = new SetUpData();
    }
    refDialog = React.createRef<PopupDialog>();
    render() {
        let style: CSSProperties = {
            position: "absolute",
            right: "0%"
        };
        return (
            <PopupDialog title="Set up a game" ref={this.refDialog}>
                <section>
                    Size of board?
                    <ul>
                        <li>
                            X:{this.state.nx}
                            <input type="range" min="10" max="100"
                                value={this.state.nx} onChange={(e) => { this.setState(Object.assign(this.state, { nx: e.target.value })); }} style={style} />
                        </li>
                        <li>
                            Y:{this.state.ny}
                            <input type="range" min="10" max="100"
                                value={this.state.ny} onChange={(e) => { this.setState(Object.assign(this.state, { ny: e.target.value })); }} style={style} />
                        </li>
                    </ul>
                </section>
                <section>
                    Can border reflect?{this.state.borderReflect?"Yes":"No"}
                    <input type="checkbox"
                        checked={this.state.borderReflect} onChange={(e) => { this.setState(Object.assign(this.state, { borderReflect: e.target.checked })); }} style={style} />
                </section>
                <section>
                    <input type="button" value="Submit" onClickCapture={this.onSubmit} style={{
                        position: "absolute",
                        right: "5%",
                        bottom: "5%"
                    }} />
                </section>
            </PopupDialog>
        );
    }
    onSubmit = (e: React.MouseEvent<HTMLInputElement>) => {
        this.props.onSubmit(this.state);
    }
}

class CurrentPlayer extends React.Component<{ style: GlobalStyle, firstPlayer: _r.Player }, { player: _r.Player }>{
    constructor(props: any) {
        super(props);
        this.state = {
            player: this.props.firstPlayer
        }
    }
    render() {
        return (<>
            Player:&nbsp;
            <span style={{ color: this.props.style.colorOfPlayer.get(this.state.player) }}>
                {this.props.style.stringOfPlayer.get(this.state.player)}
            </span>
        </>);
    }
}

export default class StandardGame extends React.Component<{ style: GameStyle }, { displayNumber: number }> {
    constructor(props: any) {
        super(props);
        this.state = {
            displayNumber: 0
        };
    }
    type = _r.TypeOfGame.Undefined;
    data = new _r.DefaultGame();
    setUpData = new SetUpData();
    refBoard = React.createRef<Board>();
    refCurrentPlayer = React.createRef<CurrentPlayer>();
    refSetUp = React.createRef<SetUp>();
    getDisplay() {
        switch (this.state.displayNumber) {
            case 0:
                return <SetUp onSubmit={this.onSubmit} ref={this.refSetUp} />;
            case 1:
                return <SetUp onSubmit={this.onSubmit} ref={this.refSetUp} />;
            case 2:
                {
                    this.data.InitBoard(this.setUpData.nx, this.setUpData.ny, _r.Player.P1, this.setUpData.borderReflect); try {
                        // Main Test Part Begin
                        let g = this.data;
                        g.AddHome(1, 1, _r.Player.P1, _r.Direction.Top);
                        g.AddHome(2, 2, _r.Player.P2, _r.Direction.Top);
                        g.AddMirror(2, 1, _r.TypeOfMirror.BackSlash, _r.Player.P1);
                        console.log("Winner = ", this.props.style.global.stringOfPlayer.get(g.WhoWins()));
                        console.log("Record = ", g.Record);
                        // Main Test Part End
                    } catch (e0: unknown) {
                        let e = e0 as Error;
                        alert("ERROR: " + e.message);
                    }
                    return <>
                        <Board
                            data={this.data.Board}
                            style={this.props.style.board}
                            eventHandlers={{
                                onMirrorClick: this.onMirrorClick,
                                onPointClick: this.onPointClick
                            }}
                            ref={this.refBoard} />
                        <CurrentPlayer
                            style={this.props.style.global}
                            firstPlayer={this.data.CurrentPlayer}
                            ref={this.refCurrentPlayer} />
                    </>;
                }
            default:
                return <></>;
        }
    }
    onMirrorClick = (coord: _r.Coord, mirror: _r.TypeOfMirror) => {
    }
    onPointClick = (coord: _r.Coord) => {
        if (this.point1Selected) {
            let x1 = this.point1Coord.x;
            let y1 = this.point1Coord.y;
            let x2 = coord.x;
            let y2 = coord.y;
            [[x1, y1], [x2, y2]] = x1 + y1 < x2 + y2 || (x1 + y1 === x2 + y2 && x1 < x2) ? [[x1, y1], [x2, y2]] : [[x2, y2], [x1, y1]];
            let dx = x2 - x1;
            let dy = y2 - y1;
            let addMirrorSucceeded = true;
            if (dx > 1 || dx < -1 || dy > 1 || dy < -1 || (dx === 0 && dy === 0)) {
                addMirrorSucceeded = false;
            } else {
                let x = x1;
                let y = y1;
                let mirrorType = _r.TypeOfMirror.Unknow;
                if (x2 !== this.data.Nx && y2 !== this.data.Ny) {
                    if (dx === 0 && dy === 1) mirrorType = _r.TypeOfMirror.Left;
                    if (dx === 1 && dy === 0) mirrorType = _r.TypeOfMirror.Top;
                    if (dx === 1 && dy === 1) mirrorType = _r.TypeOfMirror.BackSlash;
                    if (dx === 1 && dy === -1) {
                        mirrorType = _r.TypeOfMirror.Slash;
                        y--;
                    }
                } else {
                    if (dx === 0 && dy === 1) {
                        mirrorType = _r.TypeOfMirror.Right;
                        x--;
                    }
                    if (dx === 1 && dy === 0) {
                        mirrorType = _r.TypeOfMirror.Bottom;
                        y--;
                    }
                    if (dx === 1 && dy === 1) mirrorType = _r.TypeOfMirror.BackSlash;
                    if (dx === 1 && dy === -1) {
                        mirrorType = _r.TypeOfMirror.Slash;
                        y--;
                    }
                }
                if (mirrorType !== _r.TypeOfMirror.Unknow) {
                    try {
                        addMirrorSucceeded = addMirrorSucceeded && this.data.AddMirror(x, y, mirrorType, this.data.CurrentPlayer, true);
                    } catch (e) {
                        if (e instanceof Error) {
                            let err = e as Error;
                            console.log("Error:", err.message, x, y, mirrorType, this.data.CurrentPlayer, false);
                            addMirrorSucceeded = false;
                        } else {
                            throw e;
                        }
                    }
                }
            }
            if (addMirrorSucceeded) {
                this.data.NextPlayer();
                this.refCurrentPlayer.current?.setState({
                    player: this.data.CurrentPlayer
                });
            }
            this.refBoard.current?.unSelectPoint(this.point1Coord);
            this.point1Selected = false;
            this.point1Coord = _r.InvalidCoord;
            this.refBoard.current?.forceUpdate();
        } else {
            this.refBoard.current?.selectPoint(coord);
            this.point1Selected = true;
            this.point1Coord = coord;
        }
    }
    point1Selected = false;
    point1Coord = new _r.Coord();
    render() {
        return (
            <DocumentTitle title="StandardGame | RayChess">
                <>
                    {this.getDisplay()}
                </>
            </DocumentTitle>
        );
    }
    onSubmit = (data: SetUpData) => {
        this.refSetUp.current?.refDialog.current?.setState({ display: "up" });
        this.setUpData = data;
        this.setState({ displayNumber: this.state.displayNumber + 1 });
        setTimeout(() => {
            this.setState({ displayNumber: this.state.displayNumber + 1 });
        }, 1000);
    }
}